/**
 * 开启 / 显示自建应用
 */
import throttle from 'lodash/throttle'
import { Modal } from '@/desktop/components'
import useUIMemory from '@/logics/memory'
import services from '@/services'
import { type ThirdApp } from '@/services/features/third-apps'

export function ShowThirdApp({
  thirdApp,
  open,
  onClose,
}: {
  thirdApp: ThirdApp
  open: boolean
  onClose: () => void
}) {
  /* 自建应用有两种：
   * - 开启 URL：对这种，开启一个新窗口，并直接触发 onClose（因为并没有一个组件真的处于渲染状态）
   * - 渲染 HTML：对这种，要在一个 modal 里渲染它
   */
  useEffect(() => {
    if (!thirdApp.html && open) {
      void services.features.thirdApps.openByURL(thirdApp.id)
      onClose()
    }
  }, [thirdApp, open, onClose])

  if (thirdApp.html) {
    return <HTMLThirdAppModal app={thirdApp} open={open} onClose={onClose} />
  }
  return null
}

type Size = { width: number; height: number }

function HTMLThirdAppModal({
  app,
  open,
  onClose,
}: {
  app: ThirdApp | null
  open: boolean
  onClose: () => void
}) {
  const [size, setSize] = useUIMemory<Size>(`third-app-size-${app?.id ?? ''}`, {
    width: 800,
    height: 500,
  })

  return <Modal
    open={open}
    title={app?.name}
    width={size.width}
    css={modalStyle}
    onCancel={onClose}
    footer={null}
  >
    {app ? <AppContent app={app} size={size} setSize={setSize} /> : null}
  </Modal>
}

function AppContent({
  app,
  size,
  setSize,
}: {
  app: ThirdApp
  size: Size
  setSize: (size: Size) => void
}) {
  const elementRef = useRef<HTMLIFrameElement>(null)
  useEffect(() => {
    const iframe = elementRef.current
    if (iframe) services.features.thirdApps.openByHTML(app.id, iframe)
  }, [app])

  const [resizing, setResizing] = useState(false)
  function onMouseDown(e: React.MouseEvent<HTMLDivElement>) {
    setResizing(true)
    startResize(e, size, setSize, () => setResizing(false))
  }

  return <div className={`app ${resizing ? 'resizing' : ''}`}>
    <iframe ref={elementRef} style={{ width: `${size.width}px`, height: `${size.height}px` }} />
    <div className="resizer" onMouseDown={onMouseDown}>
      <div></div>
    </div>
  </div>
}

function startResize(
  e: React.MouseEvent<HTMLDivElement>,
  initialSize: Size,
  setSize: (size: Size) => void,
  onFinish: () => void,
) {
  console.log('start resize')
  let stopped = false

  const minWidth = 300
  const maxWidth = document.body.offsetWidth * 0.8
  const minHeight = 300
  const maxHeight = document.body.offsetHeight * 0.7

  const initialPos = { x: e.clientX, y: e.clientY }
  function updateSize(e: MouseEvent) {
    // 坐标限制在页面范围内
    const pos = {
      x: Math.min(Math.max(e.clientX, 0), document.body.offsetWidth),
      y: Math.min(Math.max(e.clientY, 0), document.body.offsetHeight),
    }
    const moved = {
      x: pos.x - initialPos.x,
      y: pos.y - initialPos.y,
    }
    const size = {
      // 因为对话框横向是居中的，必须放大/缩小双倍距离，才能匹配鼠标停止的位置
      width: Math.min(Math.max(initialSize.width + moved.x * 2, minWidth), maxWidth),
      height: Math.min(Math.max(initialSize.height + moved.y, minHeight), maxHeight),
    }
    setSize(size)
  }
  // 鼠标刚移动时还没必要 resize，所以不需要 leading
  // 移动完全结束时固定会收一次尾，所以也不需要 trailing
  const throttleUpdateSize = throttle(updateSize, 50, { leading: false, trailing: false })

  function onMouseMove(e: MouseEvent) {
    e.preventDefault() // 避免在有滚动条时拖动鼠标触发滚动条滚动
    throttleUpdateSize(e)
  }
  function onMouseUp(e: MouseEvent) {
    if (stopped) return
    stopped = true

    document.body.removeEventListener('mousemove', onMouseMove)
    document.body.removeEventListener('mouseup', onMouseUp)
    document.body.removeEventListener('mouseleave', onMouseUp)

    updateSize(e)
    onFinish()
  }

  document.body.addEventListener('mousemove', onMouseMove)
  document.body.addEventListener('mouseup', onMouseUp)
  document.body.addEventListener('mouseleave', onMouseUp)
}

const modalStyle = css`
  .ant-modal-content {
    padding: 0;
  }
  .ant-modal-header {
    padding: 20px 24px 0;
  }

  .app {
    position: relative;
  }
  .resizer {
    bottom: 0;
    height: 32px;
    position: absolute;
    right: 0;
    width: 32px;
    cursor: nwse-resize;
    border-top: 1px solid #333;
    padding: 8px 8px;
    transform: rotate(-45deg) scale(0.5) translate(0px, 32px);
    div {
      border-top: 1px solid #333;
    }
  }
  .resizing iframe {
    pointer-events: none; // 避免 iframe 吞掉鼠标事件
  }

  iframe {
    border: none;
    display: block;
  }
`
